package com.secsbrain.development.web.controller;

import com.secsbrain.cmdb.client.iface.AppInfoService;
import com.secsbrain.cmdb.client.model.SystemTypeEnums;
import com.secsbrain.common.ErrorCodeEnum;
import com.secsbrain.common.ResponseResult;
import com.secsbrain.common.utils.RedisUtil;
import com.secsbrain.deploy.client.iface.ModelService;
import com.secsbrain.development.biz.AppService;
import com.secsbrain.development.remote.SsoRemoteService;
import com.secsbrain.development.web.dto.AppQuery;
import com.secsbrain.sso.core.SsoHelper;
import com.secsbrain.sso.model.dto.system.RoleDTO;
import com.secsbrain.sso.model.dto.system.UserDetailDTO;
import com.secsbrain.development.web.dto.DeployDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import com.alibaba.fastjson.JSON;
import com.secsbrain.common.ResponseVo;
import com.secsbrain.cmdb.client.model.App;
import com.secsbrain.cmdb.client.model.AppDetail;
import com.secsbrain.cmdb.client.model.Server;
import com.secsbrain.deploy.client.model.BuildModelDto;
import com.secsbrain.deploy.client.model.DeployParam;
import com.secsbrain.development.web.dto.AppDetailDTO;
import com.secsbrain.development.web.dto.AppDetailDTO.DeploymentInfo;
import springfox.documentation.annotations.ApiIgnore;

import java.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

@RestController
@RequestMapping("api/app")
@Api(value = "app", tags = "应用管理")
public class AppController {

    private static final Logger logger = LoggerFactory.getLogger(AppController.class);

    @Value("${admin.roleCode:}")
    private String adminRoleCode;

    @Value("${admin2.roleCode:}")
    private String admin2RoleCode;

    @Value("${ops.roleCode:}")
    private String opsRoleCode;

    @Autowired
    ModelService buildModelService;

    @Autowired
    AppInfoService appInfoService;

    @Autowired
    SsoRemoteService permissionServiceFacade;

    @Autowired
    AppService appService;

    private Map<String, Map<Long, BuildModelDto>> appIdBuildMapEnv(Map<String, List<BuildModelDto>> envListMap) {
        Map<String, Map<Long, BuildModelDto>> resultMap = new HashMap<>();
        if (envListMap.isEmpty()) {
            return resultMap;
        }

        Set<Map.Entry<String, List<BuildModelDto>>> entrySet = envListMap.entrySet();
        for (Map.Entry<String, List<BuildModelDto>> entry : entrySet) {
            Map<Long, BuildModelDto> map = new HashMap<>();
            if (entry.getValue() == null) {
                continue;
            }
            for (BuildModelDto model : entry.getValue()) {
                map.put(model.getAppId(), model);
            }

            resultMap.put(entry.getKey(), map);
        }

        return resultMap;
    }

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ApiOperation(value = "查询应用列表", notes = "查询应用列表")
    public ResponseResult<List<AppDetailDTO>> appList(Integer page, Integer limit, AppQuery appQuery) {
        UserDetailDTO userDetailDTO = SsoHelper.currentUser();
        List<RoleDTO> roleList = userDetailDTO.getUserRoleList();
        Long userId = userDetailDTO.getId();
        for (RoleDTO roleDTO : roleList) {
            if (admin2RoleCode.equals(roleDTO.getCode()) || adminRoleCode.equals(roleDTO.getCode()) || opsRoleCode.equals(roleDTO.getCode())) {
                userId = null;
                break;
            }
        }

//        logger.debug("是否存在redis key deploy_app_key：" + RedisUtil.kExists(App.APP_REDIS_KEY + userId));
//        if (RedisUtil.kExists(App.APP_REDIS_KEY)) {
//            return new ResponseResult(JSON.parseArray(RedisUtil.get(App.APP_REDIS_KEY + userId), AppDetailDTO.class));
//        }

        ResponseVo<List<App>> appListVo = appInfoService.queryAllAppList(page, limit, "", "", appQuery.getAppName(), appQuery.getAppType());
        if (!appListVo.isSuccess()) {
            logger.error("查询应用列表失败：" + appListVo.getMsg());
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "查询应用列表失败：" + appListVo.getMsg());
        }

        List<AppDetailDTO> resultList = new ArrayList<>();
        List<App> appList = appListVo.getData();
        List<Long> appIdList = new ArrayList<>();
        for (App app : appList) {
            Map<Long, Object> devIdMap = new HashMap<>();
            devIdMap.put(app.getOwnerId(), true);
            for (Long developerId : app.getDeveloperIdList()) {
                devIdMap.put(developerId, true);
            }
            if (userId != null && !devIdMap.containsKey(userId)) {
                continue;
            }
            appIdList.add(app.getId());
        }

        if (CollectionUtils.isEmpty(appIdList)) {
            //用户没有应用列表直接返回
            return new ResponseResult<>(resultList);
        }

        //appId 列表
        Long[] appIds = appIdList.toArray(new Long[0]);
        //查询应用详情列表
        ResponseVo<List<AppDetail>> appDetailListVo = appInfoService.queryAppDetailByIds(appIds);
        if (!appDetailListVo.isSuccess()) {
            logger.error("查询应用失败：" + appDetailListVo.getMsg());
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "查询应用失败：" + appDetailListVo.getMsg());
        }

        List<AppDetail> appDetailList = appDetailListVo.getData();
        Set<String> envSet = new HashSet<>();
        for (AppDetail appDetail : appDetailList) {
            List<Server> serverList = appDetail.getServerList();
            for (Server server : serverList) {
                envSet.add(server.getEnvName());
            }
        }

        Map<String, Map<Long, BuildModelDto>> appIdBuildMapEnvMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(envSet)) {
            Map<String, List<BuildModelDto>> map = new HashMap<>();
            for (String envName : envSet) {
                try {
                    ResponseVo<List<BuildModelDto>> buildModelDtoListVo = buildModelService.queryAllBuildModelByEnv(envName);
                    List<BuildModelDto> buildRecordList = buildModelDtoListVo.getData();
                    map.put(envName, buildRecordList);
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
            appIdBuildMapEnvMap = appIdBuildMapEnv(map);
        }

        for (AppDetail appDetail : appDetailList) {
            AppDetailDTO appDetailDTO = new AppDetailDTO();
            appDetailDTO.setAppDesc(appDetail.getDesc());
            appDetailDTO.setAppType(appDetail.getSystemType());
            appDetailDTO.setAppName(appDetail.getName());
            appDetailDTO.setLevel(appDetail.getLevel());

            List<DeploymentInfo> deploymentList = new ArrayList<>();

            List<Server> serverList = appDetail.getServerList();
            if (CollectionUtils.isNotEmpty(serverList)) {
                for (Server server : serverList) {
                    DeploymentInfo deploymentInfo = new DeploymentInfo();
                    deploymentInfo.setEnv(server.getEnvName());
                    deploymentInfo.setServerHostName(server.getHostName());
                    deploymentInfo.setServerId(server.getHostId());

                    if (appIdBuildMapEnvMap.containsKey(server.getEnvName())) {
                        if (appIdBuildMapEnvMap.get(server.getEnvName()).containsKey(appDetail.getId())) {
                            appDetailDTO.setHasEnv(true);
                            deploymentInfo.setDeployParam(this.parseBuildModelDto(appIdBuildMapEnvMap.get(server.getEnvName()).get(appDetail.getId())));
                        }
                    }
//                		deploymentInfo.setDeploying(deploying); TODO 是否在发布的功能后续再做
                    deploymentList.add(deploymentInfo);
                }
            }
            appDetailDTO.setDeploymentList(deploymentList);

            App app = new App();
            app.setId(appDetail.getId());
            app.setName(appDetail.getName());
            app.setSystemType(appDetail.getSystemType());
            appDetailDTO.setApp(app);
            appDetailDTO.setAppOwnerName(appDetail.getOwnerName());
            appDetailDTO.setGitUrl(appDetail.getGitUrl());
            appDetailDTO.setId(appDetail.getId());


            resultList.add(appDetailDTO);
        }

//        RedisUtil.put(App.APP_REDIS_KEY + userId, JSON.toJSONString(resultList));
        ResponseResult responseResult = new ResponseResult<>(resultList);
        responseResult.setTotal(appListVo.getTotalProperty());
        return responseResult;

    }

    private DeployParam parseBuildModelDto(BuildModelDto buildModelDto) {
        DeployParam deployParam = new DeployParam();
        deployParam.setAppId(buildModelDto.getAppId());

        try {
            @SuppressWarnings("rawtypes")
            Map map = JSON.parseObject(buildModelDto.getModelJson(), Map.class);
            deployParam.setBuildCmd(map.containsKey("buildCmd") ? (String) map.get("buildCmd") : null);
            deployParam.setRemoteCmdPath(map.containsKey("remoteCmdPath") ? (String) map.get("remoteCmdPath") : null);
            deployParam.setRemoteFloder(map.containsKey("remoteFloder") ? (String) map.get("remoteFloder") : null);
            deployParam.setTargetPath(map.containsKey("targetPath") ? (String) map.get("targetPath") : null);
            deployParam.setSwitchflow(map.containsKey("switchflow") ? (Boolean) map.get("switchflow") : null);
            deployParam.setK8s(map.containsKey("k8s") ? (Boolean) map.get("k8s") : false);
            deployParam.setSwitchEnvName(map.containsKey("switchEnvName") ? (String) map.get("switchEnvName") : null);
            deployParam.setApplicationName(map.containsKey("applicationName") ? (String) map.get("applicationName") : null);
            deployParam.setRegistCenterUrl(map.containsKey("registCenterUrl") ? (String) map.get("registCenterUrl") : null);
            deployParam.setJvmOps(map.containsKey("jvmOps") ? (String) map.get("jvmOps") : null);
            deployParam.setJavaOps(map.containsKey("javaOps") ? (String) map.get("javaOps") : null);
            deployParam.setPort(map.containsKey("port") ? (Integer) map.get("port") : null);
            deployParam.setWaitTime(map.containsKey("waitTime") ? (Integer) map.get("waitTime") : null);

        } catch (Exception e) {
            logger.error("", e);
        }
        return deployParam;
    }

    @RequestMapping(value = "/branch/{id}/{env}", method = RequestMethod.GET)
    @ApiOperation(value = "获取应用分支", notes = "获取应用分支")
    public ResponseResult<List<String>> branchList(@ApiParam("应用ID") @PathVariable("id") long id, @ApiParam("环境名称") @PathVariable("env") String env) {
        List<String> branchList = appService.fetchBranchByAppId(id, env);
        if (branchList != null) {
            return new ResponseResult<>(branchList);
        } else {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "获取分支失败，请稍后重试！");
        }
    }

    /**
     * @api {POST} /api/app/newOrUpdate  新增/修改应用模型
     * @apiGroup CONFIG
     * @apiParam {Number{1}} flag          		0-新增，1-修改
     * @apiParam {Number{11}}  appId       		应用ID
     * @apiParam {Boolean}  switchflow     		是否切流（分组）发布
     * @apiParam {String{20}} [sfEnv]           切流环境名称
     * @apiParam {String{200}} [targetPath]		目标路径，如/engine-service/target/engine-service.jar
     * @apiParam {String{200}} [remoteFloder]	接收文件的远程文件夹，如/opt/jar/engine
     * @apiParam {String{200}} [remoteCmdPath]	远程启动命令路径，如/opt/sh/engine/deploy.sh
     * @apiParam {String{32}} [buildCmd]        编译命令，如build:sit
     * @apiParam {String{150}} [eurekaUrl]    	eureka地址，如http://10.0.11.79:8762
     * @apiParam {Number{4}} [port]            	端口号，如8080
     * @apiParam {String{20}} [applicationName] spring应用名，如service-engine
     * @apiParam {Number{5}} [waitTime]         下线后等待时间（秒）
     */
    @ApiOperation(value = "新增/修改应用模型", notes = "新增/修改应用模型")
    @RequestMapping(value = "/newOrUpdate", method = RequestMethod.POST)
    public ResponseResult<?> newOrUpdate(@Valid @RequestBody DeployDTO deployDTO, HttpServletRequest servletRequest) {
        UserDetailDTO userDetailDTO = SsoHelper.currentUser();
        String appCode = servletRequest.getHeader("appCode");
        if (StringUtils.isBlank(appCode)) {
            appCode = servletRequest.getParameter("appCode");
        }
        List<RoleDTO> roleList = permissionServiceFacade.getRoleListByUserId(appCode, userDetailDTO.getId()).getData();
//        if (CollectionUtils.isEmpty(roleList) || !adminRoleCode.equals(roleList.get(0).getCode())) {
//            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "只有管理员才有权限操作");
//        }

        DeployParam deployParam = new DeployParam();
        BeanUtils.copyProperties(deployDTO, deployParam);

        deployParam.setJvmOps(deployDTO.getJvmOption());
        deployParam.setJavaOps(deployDTO.getJavaOption());
        deployParam.setSwitchEnvName(deployDTO.getSfEnv());
        deployParam.setK8sFlag(deployDTO.isK8s());
        deployParam.setEnvName(deployDTO.getEnvName());

        ResponseVo<?> responseVo = null;
        if (deployDTO.getFlag() == 0) {
            responseVo = buildModelService.createDeployJob(deployParam);
        } else {
            responseVo = buildModelService.updateDeployJob(deployParam);
        }

        if (!responseVo.isSuccess()) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), responseVo.getMsg());
        }
        RedisUtil.remove(App.APP_REDIS_KEY);
        return new ResponseResult<>();
    }

    @RequestMapping(value = "/delete/{id}/{envName}", method = RequestMethod.GET)
    @ApiIgnore
    public ResponseResult<?> delete(long id, @PathVariable("envName") String envName, HttpServletRequest servletRequest) {
        UserDetailDTO userDetailDTO = SsoHelper.currentUser();
        String appCode = servletRequest.getHeader("appCode");
        if (StringUtils.isBlank(appCode)) {
            appCode = servletRequest.getParameter("appCode");
        }
        List<RoleDTO> roleList = permissionServiceFacade.getRoleListByUserId(appCode, userDetailDTO.getId()).getData();
        if (CollectionUtils.isEmpty(roleList) || !adminRoleCode.equals(roleList.get(0).getCode())) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "只有管理员才有权限操作");
        }

        DeployParam deployParam = new DeployParam();
        deployParam.setAppId(id);
        ResponseVo<?> responseVo = buildModelService.deleteDeployJob(deployParam);
        if (!responseVo.isSuccess()) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), responseVo.getMsg());
        } else {
            RedisUtil.remove(App.APP_REDIS_KEY);
            return new ResponseResult<>();
        }
    }

    @ApiOperation(value = "查询应用类型", notes = "查询应用类型")
    @RequestMapping(value = "types", method = RequestMethod.GET)
    public ResponseResult<List<String>> appTypes() {
        List<String> resultList = new ArrayList<>();
        for (SystemTypeEnums systemTypeEnum : SystemTypeEnums.values()) {
            resultList.add(systemTypeEnum.toString());
        }
        return new ResponseResult<>(resultList);
    }

}
